package com.gitee.l0km.aocache;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import com.gitee.l0km.aocache.ContextHolder.AocacheContext;
import com.gitee.l0km.aocache.annotations.AoWeakCacheable;
import com.gitee.l0km.aocache.config.CacheConfig;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.FluentIterable;

/**
 * <p>
 * 复合键缓存抽象类，用于管理具有多个唯一标识字段（如数据库表的主键和唯一键）的数据对象缓存。
 * 典型应用场景：
 * <ul>
 *   <li>数据库表对象缓存 - 当表记录更新时，自动同步更新所有关联键（主键/唯一键）的缓存项</li>
 *   <li>多维度查询缓存 - 支持通过不同唯一标识组合快速检索缓存对象</li>
 *   <li]级联缓存更新 - 修改父级缓存时自动更新所有关联子缓存，保持数据一致性</li>
 * </ul>
 * </p>
 * <p>
 * 实现特性：
 * <ul>
 *   <li>支持级联缓存结构，通过父子缓存联动实现多键同步管理</li>
 *   <li>提供线程安全的读写锁机制，确保并发环境下的数据一致性</li>
 *   <li>要求子类实现关键方法：
 *     <ul>
 *       <li>{@link #getArgs(Object)} - 从缓存对象提取复合键参数</li>
 *       <li>{@link #isValidArgs(Object[])} - 验证键参数有效性</li>
 *       <li>{@link #compute(Object[])} - 定义缓存缺失时的计算逻辑</li>
 *     </ul>
 *   </li>
 * </ul>
 * </p>
 * <p>
 * 示例场景：
 * 用户表(user_id主键, username唯一键)缓存更新时，通过本类可自动同步更新：
 * <pre>{@code
 * - user_id:1001 的缓存
 * - username:"john_doe" 的缓存
 * }</pre>
 * </p>
 * 
 * @param <C> 缓存值类型
 * @author guyadong
 */
public abstract class CompositeKeyCache<C> {
	/**
	 * 默认的 {@link #doGet(Object[])} 方法使用的缓存配置对象。
	 */
	private static final CacheConfig DEFAULT_DOGET_CONFIG = new CacheConfig()
			.weakValues(true)
			.maximumSize(100)
			.expireAfterAccess(60, TimeUnit.SECONDS);
	/**
	 * <p>表示 {@link CompositeKeyCache} 类中的 {@link #doGet(Object[])} 方法的反射对象。</p>
	 * <p>该对象在静态代码块中通过反射机制获取，用于后续与缓存操作相关的处理。</p>
	 */
	public static final Method DOGET_METHOD;
	static {
		try {
			DOGET_METHOD = CompositeKeyCache.class.getDeclaredMethod("doGet", Object[].class);
		} catch (NoSuchMethodException | SecurityException e) {
			throw new RuntimeException(e);
		}
	}
    private final AtomicReference<InvokeCache> invokeCache = new AtomicReference<>();
	/**
	 * <p>
	 * 指向当前级联缓存的父级缓存实例。
	 * </p>
	 * <p>
	 * 父级缓存用于管理子级缓存，在缓存更新、清除等操作时可能会涉及到父级缓存与子级缓存之间的联动。
	 * 当当前缓存为子级缓存时，该属性会被设置为对应的父级缓存；若当前缓存为主缓存，则该属性可能为 null。
	 * </p>
	 */
	private CompositeKeyCache<C> parent;
    /** 缓存名称, 为null 表示主键缓存 */
    protected final String name;
    protected final MemberKey memberKey;
	/**
	 * <p>缓存配置对象，用于存储和管理缓存的相关配置信息。</p>
	 * <p>该配置对象包含了缓存的各种参数，如最大缓存大小、缓存过期时间、移除监听器等。</p>
	 * <p>若该对象为 null，则表示使用默认的缓存配置。</p>
	 * <p>当前类没有引用该对象，提供给子类引用。</p>
	 */
	protected final CacheConfig config;
    private final ReentrantReadWriteLock lock;
    protected final Map<String, CompositeKeyCache<C>> childCachesByName;

	/**
	 * <p>
	 * 构造一个复合键缓存实例，允许指定缓存名称、缓存配置和级联子缓存数组。
	 * </p>
	 * <p>
	 * 该构造函数会根据传入的参数初始化缓存的基本属性，包括缓存名称、读写锁、成员键、缓存配置以及子缓存映射。
	 * 同时会对传入的参数进行有效性检查，确保父缓存和缓存名称的组合符合规则。
	 * </p>
	 * 当 {@code childCaches} 为 {@code null} 时，认为当前缓存为子级缓存，此时 {@code name} 必须不为 {@code null}；<br>
	 * 当 {@code childCaches} 不为 {@code enull} 时，认为当前缓存为主键缓存，此时 {@code name} 必须为 {@code null}。
	 * 会忽略数组中为 {@code null}的元素 数组元素不能是主键缓存(parent为{@code null})<br>
	 * @param name 缓存名称，为 {@code null} 表示主键缓存。
	 * @param config 缓存配置信息，可为 {@code null}，若为 {@code null} 则使用默认配置。
	 * @param childCaches 可选的级联子缓存数组。
	 */
	@SuppressWarnings("unchecked")
	protected CompositeKeyCache(String name, CacheConfig config, CompositeKeyCache<C>[] childCaches) {
		this.name = name;
		this.lock = null != name ? null : new ReentrantReadWriteLock();
		this.memberKey = MemberKey.of(DOGET_METHOD, this);
		this.config = null == config ? DEFAULT_DOGET_CONFIG.clone() : config;
		if ((this instanceof AocacheRemovalListener) && null == this.config.removalListener()) {
			config.removalListener((AocacheRemovalListener<Object, Object>) this);
		}
		MemberCache.INSTANCE.setCacheConfig(memberKey.member, memberKey.target, config);
		if (null == childCaches) {
			/** 当为子级缓存时，name 字段必须不为 null */
			checkState(null != name, "name must not be null when childCaches is null");
			this.childCachesByName = Collections.emptyMap();
		} else {
			/** 当为主键缓存时，name 字段必须为 null */
			checkState(null == name, "name must be null when childCaches is not null");
			/** 使用LinkedHashMap 保持插入顺序 */
			Map<String, CompositeKeyCache<C>> map = new LinkedHashMap<>();
			/** 设置父级缓存 */
			for (int i = 0; i < childCaches.length; i++) {
				CompositeKeyCache<C> childCache = childCaches[i];
				if(null != childCache){
					checkNotNull(childCache.name, "childCaches[%s].name can not be null", i);
					checkState(null == childCache.parent, "childCaches[%s] can not be a primary cache", i);
					childCache.parent = this;
					map.put(childCache.getName(), childCache);
				}
			}
			this.childCachesByName = Collections.unmodifiableMap(map);
		}
	}
	/**
	 * <p>
	 * 构造一个级联缓存实例。
	 * </p>
	 * <p>
	 * 该构造函数用于初始化级联缓存，需要提供缓存名称、目标对象以及缓存配置。
	 * 会对传入的参数进行检查，确保父缓存和缓存名称的组合符合规则。
	 * </p>
	 * @param name 缓存名称，为 null 表示主键缓存。
	 * @param config 缓存配置信息，可为 null。
	 */
	protected CompositeKeyCache(String name, CacheConfig config){
		this(checkNotNull(name, "name is null"), config, null);
    }
	/**
	 * <p>
	 * 构造一个主缓存实例。
	 * </p>
	 * <p>
	 * 该构造函数用于初始化主缓存，需要提缓存配置以及可选的级联缓存数组。
	 * 它会对传入的级联缓存进行验证，确保级联缓存不为空且不是 PrimaryCache 类型。
	 * </p>
	 * @param config         缓存配置信息，可为 null。
	 * @param childCaches 可选的级联缓存数组，数组中的元素不可为 null 且不能是 PrimaryCache 类型。
	 */
	@SuppressWarnings("unchecked")
	protected CompositeKeyCache(CacheConfig config, CompositeKeyCache<C>... childCaches) {
		this(null, config, childCaches);
	}
	protected void readLock() {
		/* 读取锁可能会带来性能损失，所以考虑禁用 */
//		if (null != lock) {
//			lock.readLock().lock();
//		}
	}
	protected void readUnlock() {
		/* 读取锁可能会带来性能损失，所以考虑禁用 */
//		if (null != lock) {
//			lock.readLock().unlock();
//		}
	}
	protected void writeLock() {
		if (null != lock) {
			lock.writeLock().lock();
		}
	}
	protected void writeUnlock() {
		if (null != lock) {
			lock.writeLock().unlock();
		}
	}
    public Map<String, CompositeKeyCache<C>> getChildCaches() {
		return childCachesByName;
	}
	public String getName() {
	    return name;
	}
	public long size() {
		return getInvokeCache().size();
	}

	/**
	 * <p>根据传入的缓存名称获取对应的缓存大小。</p>
	 * <p>如果传入的名称与当前缓存的名称相同，则返回当前缓存的大小；</p>
	 * <p>否则，从级联子缓存中查找对应的子缓存，并返回该子缓存的大小。</p>
	 * <p>如果找不到对应的子缓存，则抛出 {@link IllegalArgumentException} 异常。</p>
	 * @param name 要查询的缓存名称
	 * @return 对应的缓存大小
	 */
	public long getCacheSizeByName(String name) {
		if (Objects.equals(name, this.name)) {
			return size();
		}
		CompositeKeyCache<C> childCache = childCachesByName.get(checkNotNull(name, "name can not be null"));
		checkArgument(null != getChildCaches().get(name), "INVALID cache name:%s", name);
		return childCache.size();
	}
    /**
	 * <p>
	 * 从输入对象中提取参数数组。
	 * 该方法为抽象方法，子类需要实现此方法来定义如何从缓存值中提取参数。
	 * </p>
	 * 
	 * @param value 缓存值，类型为泛型 C。
	 * @return 从缓存值中提取的参数数组。如果传入的缓存值为 null，则返回 null。
	 */
	protected abstract Object[] getArgs(C value);

	/**
	 * <p>
	 * 从传入的缓存值中提取用于生成缓存键的参数数组。
	 * </p>
	 * <p>
	 * 该方法会调用 {@link #getArgs(C)} 方法获取基础参数，然后对其进行包装处理，最终返回用于生成缓存键的参数数组。
	 * </p>
	 * 
	 * @param value 缓存值，类型为泛型 C。如果传入 null，可能会导致 {@link #getArgs(C)} 方法返回 null。
	 * @return 用于生成缓存键的参数数组。
	 */
	private final Object[] getArgs4Key(C value) {
		return null == value ? null : wrapArgs4Key(getArgs(value));
	}
	private InvokeCache getInvokeCache() {
        if(invokeCache.get() == null) {
            try {
				invokeCache.compareAndSet(null, MemberCache.INSTANCE.get(memberKey));
			} catch (Throwable e) {
				Throwables.throwIfUnchecked(e);
				throw new RuntimeException(e);
			}
        }
        return invokeCache.get();
    }

	protected boolean hasValidArgs(C value) {
		return isValidArgs(getArgs(value));
	}

	/**
	 * <p>
	 * 查找第一个对于给定值具有无效参数的缓存实例。
	 * </p>
	 * <p>
	 * 该方法会递归检查当前缓存的父级缓存，若存在父级缓存，则先从父级缓存开始查找。
	 * 若当前缓存不是已知具有有效参数的缓存，且对于给定值的参数无效，则返回当前缓存。
	 * 若当前缓存不符合条件，则会遍历所有子级缓存，查找第一个对于给定值具有无效参数的子级缓存。
	 * 如果都没有找到，则返回 null。
	 * </p>
	 * 
	 * @param value 用于检查参数有效性的缓存值。
	 * @param knownCacheWithValidArgs 已知对于给定值具有有效参数的缓存实例。避免重复检查。
	 * @return 第一个对于给定值具有无效参数的缓存实例，如果未找到则返回 null。
	 */
	private CompositeKeyCache<C> findFirstCacheForInvalidArgs(C value, CompositeKeyCache<C> knownCacheWithValidArgs) {
		if (null != parent) {
			return parent.findFirstCacheForInvalidArgs(value, knownCacheWithValidArgs);
		}
		if (knownCacheWithValidArgs != this && !hasValidArgs(value)) {
			return this;
		}
		for (CompositeKeyCache<C> childCache : childCachesByName.values()) {
			if (knownCacheWithValidArgs != childCache && !childCache.hasValidArgs(value)) {
				return childCache;
			}
		}
		return null;
	}
    protected abstract boolean isValidArgs(Object[] args);
    /**
     * <p>
     * 检查传入的参数数组是否有效。
     * </p>
     * 子类可以重写此方法来定义参数数组的有效性检查逻辑。
     * 默认实现简单地检查参数数组是否为 null。
     *
     * @param args 待检查的参数数组
     * @return 如果参数数组不为 null，则返回 true；否则返回 false。
     */
	protected final boolean isValidWrapKey(Object[] args) {
		if (args != null && args.length == 1 && args[0] instanceof Object[]) {
			return isValidArgs((Object[]) args[0]);
		}
		return false;
	}
    protected void checkArgs(Object[] args) {
        if(!isValidArgs(args)) {
            throw new IllegalArgumentException("args can not be null");
        }
    }
    protected void checkArgs4Key(Object[] args) {
    	if(!isValidWrapKey(args)) {
    		throw new IllegalArgumentException("args can not be null");
    	}
    }

	/**
	 * 尝试基于 {@code from} 对象将 {@code to} 合成为完整值。 
	 * 该方法用于处理缓存对象值合成为完整对象操作，具体的合成逻辑由子类实现。<br>
	 * 返回值表示合成操作是否成功。如果 {@code to} 对象被合成为完整值，则返回 {@code true}；否则返回 {@code false}。<br>
	 * 
	 * 
	 * @param to   非 {@code null} 目标对象，类型为泛型 {@code C}，用于接收合成后的值。
	 * @param from 非 {@code null} 源对象，类型为泛型 {@code C}，提供用于合成的完整值。
	 * @return 如果合成操作成功，返回 {@code true}；否则返回 {@code false}。
	 */
	protected boolean doSynthesizeIntegralValue(C to, C from) {
		return false;
	}
	/**
	 * <p>
	 * 尝试基于 {@code from} 对象将 {@code to} 合成为完整值。<br>
	 * 该方法会先检查 {@code to} 和 {@code from} 是否都不为 null，若都不为 null，则调用 {@link #doSynthesizeIntegralValue(C, C)} 方法进行合成操作。<br>
	 * 返回值表示合成操作是否成功。如果 {@code to} 对象被合成为完整值，则返回 {@code true}；否则返回 {@code false}。
	 * </p>
	 * 
	 * @param to 目标对象，类型为泛型 {@code C}，用于接收合成后的值。
	 * @param from 源对象，类型为泛型 {@code C}，提供用于合成的完整值。
	 * @return 如果合成操作成功，返回 {@code true}；否则返回 {@code false}。
	 */
	private final boolean synthesizeIntegralValue(C to, C from) {
		if(null != to && null != from){
			return doSynthesizeIntegralValue(to, from);
		}
		return false;
	}

	/**
	 * <p>
	 * 当缓存更新策略为 ALWAYS 或者 REPLACE 时，此方法会在缓存更新完成后被调用。
	 * </p>
	 * <p>
	 * 该方法可用于执行一些缓存更新完成后的额外操作，例如记录日志、触发其他相关缓存的更新等。
	 * </p>
	 * 
	 * @param cacheValue 更新到缓存中的值，类型为泛型 C。
	 */
	protected void onCacheDone(C cacheValue) {
	}

	/**
	 * <p>
	 * 根据传入的参数数组执行计算的抽象方法。
	 * </p>
	 * <p>
	 * 该方法为抽象方法，子类需要实现此方法来定义具体的计算逻辑。
	 * 计算过程中可能会抛出异常，调用者需要处理这些异常。
	 * </p>
	 * NOTE:因为所有关联缓存的key都要从value中获取，所以要求返回值为非null的值，否则必须抛出异常
	 * 
	 * @param args 用于执行计算的参数数组
	 * @return 计算结果，类型为泛型 C
	 * @throws Exception 执行计算过程中发生异常
	 */
	protected abstract C compute(Object[] args) throws Exception;
	/**
	 * <p>
	 * 从缓存中获取与指定参数数组对应的缓存值的抽象方法。
	 * 子类需要实现此方法来定义具体的缓存获取逻辑。
	 * </p>
	 * @param args 用于查找缓存值的参数数组
	 * @return 缓存中与参数数组对应的缓存值，类型为泛型 C
	 * @throws ComputeException 执行计算过程中发生异常封装为 {@link ComputeException} 抛出。
	 */
	@AoWeakCacheable
	private final C doGet(Object[] args) throws ComputeException {
		try {
			return checkNotNull(compute(args), "compute value can not be null") ;
		} catch (Exception e) {
			throw new ComputeException(e);
		}
	}


	/**
	 * <p>
	 * 尝试从缓存中获取与指定参数对应的缓存值，如果缓存中不存在，则调用 {@link #compute(Object[])} 方法进行计算并将结果存入缓存。
	 * </p>
	 * <p>
	 * 具体步骤如下：
	 * <li>检查传入的参数是否有效，如果无效则抛出 {@link IllegalArgumentException} 异常。</li>
	 * <li>获取读锁，确保在读取缓存时的线程安全。</li>
	 * <li>尝试从缓存中获取值，如果缓存中不存在，则调用 {@link #doGet(Object[])} 方法进行计算。</li>
	 * <li>释放读锁。</li>
	 * <li>如果当前处于计算调用上下文中，则使用缓存的原始非空对象更新所有关联的缓存，确保缓存同步。</li>
	 * </p>
	 * 
	 * @param args 用于查找缓存值或进行计算的参数数组
	 * @return 缓存中与参数对应的缓存值，或者计算得到的结果
	 * @throws ComputeException 执行计算过程中发生异常时抛出该异常
	 */
	protected C getCacheOrCompute(Object... args) throws ComputeException {
		try {
			checkArgs(args);
		} catch (ComputeException e) {
			throw e;
		}catch (Exception e) {
			throw new ComputeException(e);
		}
		readLock();
		C value;
		/** 获取本地上下文，如果为空，则创建一个新上下文 */
		AocacheContext ctx = ContextHolder.getLocalContext();
		try {
			value = doGet(args);
		} finally {
			readUnlock();
		}
		if (ctx.isComputeInvocation()) {
			/** 计算完成后，使用缓存的原始非null对象更新所有关联的缓存，确保缓存同步 */
			C originalCachedValue = getIfPresent(args);
			updateCache(UpdateStrategy.ALWAYS, originalCachedValue, true, name, true);
		}
		return value;
	}

	/**
	 * <p>
	 * 根据指定的缓存名称和参数，尝试从缓存中获取对应的值，如果缓存中不存在，则调用 {@link #compute(Object[])} 方法进行计算并将结果存入缓存。
	 * </p>
	 * <p>
	 * 具体步骤如下：
	 * <li>检查传入的缓存名称是否与当前缓存名称相同，如果相同，则直接调用 {@link #getCacheOrCompute(Object...)} 方法获取缓存值。</li>
	 * <li>如果缓存名称不同，则从级联缓存中查找对应的缓存实例。</li>
	 * <li>如果找到对应的级联缓存实例，则调用其 {@link #getCacheOrCompute(Object...)} 方法获取缓存值。</li>
	 * </p>
	 * 
	 * @param name 缓存名称，用于指定要查找的缓存实例。不能为 null。
	 * @param args 用于查找缓存值或进行计算的参数数组。
	 * @return 缓存中与指定名称和参数对应的缓存值，或者计算得到的结果。
	 * @throws IllegalArgumentException 如果传入的缓存名称为 null 或者未找到对应的级联缓存实例。
	 * @throws ComputeException 执行计算过程中发生异常时抛出该异常。
	 */
	protected C getCacheOrComputeByName(String name, Object... args) {
		if(Objects.equals(name, this.name)){
			return getCacheOrCompute(args);
		}
		CompositeKeyCache<C> childCache =  childCachesByName.get(checkNotNull(name, "name can not be null"));
		return checkNotNull(childCache, "cascaded cache not found by name: %s", name).getCacheOrCompute(args);
    }
    @SuppressWarnings("unchecked")
	protected C getIfPresentUncheck0(Object[] args) {
        return (C) getInvokeCache().getValueOrNull(new InvokeKey(args));
    }
	protected C getIfPresentUncheck0(C value) {
		Object[] args = getArgs4Key(value);
		if(isValidWrapKey(args)) {
			return getIfPresentUncheck0(args);
		}
		return null;
	}
	protected C getIfPresent(Object[] args) {
		readLock();
		try {
			return getIfPresentUncheck0(wrapArgs4Key(args));	
		} finally {
			readUnlock();
		}
	}

	protected C getByNameIfPresent0(String name, Object[] args) {
		if (Objects.equals(name, this.name)) {
			return getIfPresentUncheck0(wrapArgs4Key(args));
		}
		return checkNotNull(childCachesByName.get(checkNotNull(name, "name can not be null")),
				"cascaded cache not found by name: %s", name).getIfPresentUncheck0(wrapArgs4Key(args));
	}
	protected C getByNameIfPresent(String name, Object[] args) {
		readLock();
		try {
			return getByNameIfPresent0(name, args);
		} finally {
			readUnlock();
		}
	}

	/**
	 * <p>
	 * 尝试从当前缓存及其所有级联缓存中移除指定值对应的缓存条目。
	 * </p>
	 * <p>
	 * 首先检查传入的值是否包含有效键，如果包含，则根据移除策略更新缓存并返回 {@code true}。
	 * 若当前缓存中未找到可移除的条目，则会递归检查所有级联缓存，只要有一个级联缓存成功移除条目，就返回 {@code true}。
	 * 如果所有检查都未成功移除任何条目，则返回 {@code false}。
	 * </p>
	 * 
	 * @param value 要从缓存中移除的缓存值，类型为泛型 C。
	 * @return 如果成功从当前缓存或任何级联缓存中移除了条目，则返回 {@code true}；否则返回 {@code false}。
	 */
	protected boolean removeCache(C value) {
		if (hasValidArgs(value)) {
			updateCache(UpdateStrategy.REMOVE, value, false, name, false);
			return true;
		}
		for (CompositeKeyCache<C> cc : childCachesByName.values()) {
			if (cc.removeCache(value)) {
				return true;
			}
		}
		return false;
	}
	/**
	 * <p>
	 * 尝试从当前缓存及其所有级联缓存中移除与指定参数数组对应的缓存条目。
	 * </p>
	 * <p>
	 * 该方法会先根据传入的参数数组尝试从缓存中获取对应的缓存值，
	 * 如果获取到缓存值，则调用 {@link #removeCache(Object)} 方法将该缓存值从缓存中移除。
	 * </p>
	 * 
	 * @param args 用于查找要移除的缓存条目的参数数组
	 */
	protected void removeCache(Object[] args) {
		C value = getIfPresent(args);
		if (null != value) {
			removeCache(value);
		}
	}
	/**
	 * <p>
	 * 尝试从指定名称的缓存及其所有级联缓存中移除与指定参数数组对应的缓存条目。
	 * </p>
	 * <p>
	 * 该方法会先根据传入的缓存名称和参数数组尝试从缓存中获取对应的缓存值，
	 * 如果获取到缓存值，则调用 {@link #removeCache(Object)} 方法将该缓存值从缓存中移除。
	 * </p>
	 * 
	 * @param name 要操作的缓存名称，用于指定要查找的缓存实例。不能为 null。
	 * @param args 用于查找要移除的缓存条目的参数数组
	 */
	protected void removeCacheByName(String name, Object[] args) {
		C value = getByNameIfPresent(name, args);
		if (null != value) {
			removeCache(value);
		}
	}
    /**
     * <p>
     * 清除当前缓存以及所有级联缓存中的所有条目。
     * </p>
     * <p>
     * 该方法会先获取写锁，确保在清除缓存的过程中不会有其他线程访问或修改缓存。
     * 然后清除当前缓存中的所有条目，接着释放写锁。
     * 最后，会递归调用所有级联缓存的 {@code clearCache} 方法，清除它们的缓存条目。
     * </p>
     */
    protected void clearCache() {
		writeLock();
		try {
			getInvokeCache().clear();
			if(null == name) {
				for (CompositeKeyCache<C> cc : childCachesByName.values()) {
					cc.clearCache();
				}
			}
		} finally {
			writeUnlock();
		}
	}

	/**
	 * <p>
	 * 获取当前缓存中所有条目的键数组列表。
	 * </p>
	 * <p>
	 * 该方法会先获取读锁以保证线程安全，然后从缓存的键集合中提取出对应的参数数组，
	 * 并将这些参数数组转换为列表返回。操作完成后会释放读锁。
	 * </p>
	 * 
	 * @return 包含当前缓存中所有条目的键数组的列表。
	 */
	protected List<Object[]> keysOfCache() {
    	readLock();
    	try {
    		return FluentIterable.from(getInvokeCache().keySet()).transform(new Function<InvokeKey, Object[]>() {
    			@Override
    			public Object[] apply(InvokeKey input) {
    				return (Object[]) input.args[0];
    			}
    		}).copyInto(new ArrayList<Object[]>());
    	} finally {
    		readUnlock();
    	}
    }

	/**
	 * <p>
	 * 刷新缓存值或尝试合成完整值的内部方法。该方法会尝试从缓存中获取与指定参数对应的缓存值，
	 * 如果获取到的缓存值可以与原始值合成完整值，则将合成标志设置为 true 并返回合成后的缓存值。
	 * 如果合成失败，则刷新缓存并返回刷新后的缓存值；若刷新后仍未获取到缓存值，则返回原始值。
	 * </p>
	 * 
	 * @param args 用于查找缓存值的参数数组，用于生成缓存键。
	 * @param origin 原始值，用于与缓存值进行合成操作，或在刷新缓存失败时作为返回值。
	 * @param synthetic 原子布尔值，用于标记是否成功合成完整值。如果合成成功，该值将被设置为 true。
	 * @return 返回合成后的缓存值、刷新后的缓存值或原始值，具体取决于操作结果。
	 */
	@SuppressWarnings("unchecked")
	private C refreshOrSynthesize0(Object[] args, C origin, AtomicBoolean synthetic) {
		InvokeCache invokeCache = getInvokeCache();
		InvokeKey key = new InvokeKey(args);
		C cacheValue = (C) invokeCache.getValueOrNull(key);
		if(synthesizeIntegralValue(cacheValue, origin)){
			synthetic.set(true);
			return cacheValue;
		}
		MemberCache.INSTANCE.update(invokeCache, false, UpdateStrategy.REFRESH, memberKey, args, null, null);
		/** 刷新后的缓存对象 */
		C value = (C) invokeCache.getValueOrNull(key.resetForNextLookup());
		if(value != null) {
			return value;
		}
		return origin;
	}
    /**
	 * <p>
	 * 内部使用的非线程安全的缓存更新方法，需要在调用方保证线程安全。该方法根据传入的更新策略更新缓存，
	 * 可以同时处理可更新的值和需要移除的值。
	 * </p>
	 * <p>
	 * 具体操作包括根据更新策略，使用传入的参数数组、可更新的值和需要移除的值，
	 * 调用 {@link MemberCache#INSTANCE} 的更新方法来更新缓存。
	 * </p>
	 * 
	 * @param updateStrategy 更新缓存的策略，用于指定如何更新缓存，不可为 null。
	 * @param args 用于更新缓存的参数数组，这些参数会被用于生成缓存键。为 null 时，不进行缓存更新。
	 * @param updateableValue 可用于更新缓存的值，类型为泛型 C。
	 * @param removeableValue 需要从缓存中移除的值，类型为泛型 C。如果为 null，则表示没有需要移除的值。
	 */
	private void updateCache0(UpdateStrategy updateStrategy, Object[] args, C updateableValue, C removeableValue) {
		Object[] removeArgs = getArgs4Key(removeableValue);
		MemberCache.INSTANCE.update(getInvokeCache(), false, updateStrategy, memberKey, args, updateableValue,
				isValidWrapKey(removeArgs) ? removeArgs : null);
	}

	private void doUpdateCache0(final UpdateStrategy updateStrategy, final C updateableValue,
			final boolean integralValue, final boolean skipPreviousCache, final CompositeKeyCache<C> previousCache,
			final C previousCachedValue, final C refreshedValueByPreviousCache) {
		if (skipPreviousCache && (this == previousCache)) {
			/** 如果指定跳过更新缓存，且当前缓存为更新缓存，则跳过更新缓存，避免重复更新缓存 */
			return;
		}
		switch (updateStrategy) {
		case REFRESH:
			if (updateableValue != refreshedValueByPreviousCache) {
				/** 执行刷新策略时，如果已经有缓存被刷新，避免重复刷新, 否则执行与REMOVE相同逻辑 */
				if (this != previousCache) {
					/** 
					 * 如果当前缓存还没有被刷新，改为执行REPLACE策略，确保所有主键及子键缓存保存的是同一对象 
					 */
					doUpdateCache0(UpdateStrategy.REPLACE, refreshedValueByPreviousCache,
							true, skipPreviousCache, previousCache,
							previousCachedValue, refreshedValueByPreviousCache);
				}else {
					/** 如果当前缓存已经被刷新，则跳过更新缓存 */
				}
				break;
			}
			/** NOTE: 没有break, 下面执行与REMOVE相同逻辑 */
		case REMOVE: {
			Object[] args = getArgs4Key(updateableValue);
			if (!isValidWrapKey(args)) {
				/**
				 * 参数无效时， 如果是主键，直接删除，否则尝试从刷新对象获取，仍然无效则直接删除
				 */
				args = null;
				if (null != parent && updateableValue != refreshedValueByPreviousCache
						&& !isValidWrapKey(args = getArgs4Key(refreshedValueByPreviousCache))) {
					args = null;
				}
			}
			updateCache0(updateStrategy, args, updateableValue, previousCachedValue);
			break;
		}
		case ALWAYS:
		case REPLACE: {
			Object[] args;
			if (!integralValue) {
				/** 非完整数据，直接删除 */
				args = null;
			} else {
				args = getArgs4Key(updateableValue);
				/**
				 * 完整数据时，如果是主键，检查主键是否有效，无效则抛出异常 否则尝试从刷新对象获取，仍然无效则直接删除
				 */
				if (null == parent) {
					checkArgs4Key(args);
				} else if (!isValidWrapKey(args)) {
					args = null;
					if (updateableValue != refreshedValueByPreviousCache 
							&& !isValidWrapKey(args = getArgs4Key(refreshedValueByPreviousCache))) {
						args = null;
					}
				}
			}
			updateCache0(updateStrategy, args, updateableValue, previousCachedValue);
			break;
		}
		default:
			throw new IllegalArgumentException("Unsupported updateStrategy: " + updateStrategy);
		}
	}
	/**
	 * 更新缓存的方法，根据不同的更新策略对缓存进行操作。
	 * <p>
	 * 该方法会根据传入的更新策略、可更新的值、是否为完整值以及前一个缓存名称来更新当前缓存和级联缓存。
	 * <br>
	 * 支持的更新策略包括：REMOVE、REFRESH、ALWAYS、REPLACE。
	 * </p>
	 * 
	 * @param updateStrategy     缓存更新策略，不可为 null。
	 * @param updateableValue    可用于更新缓存的值，不可为 null。
	 * @param integralValue      指示传入的值{code updateableValue}是否为完整值。
	 * @param previousCacheName  用于获取旧缓存值的缓存的名称，为 null，则使用主缓存。
	 * @param skipPreviousCache  是否跳过previousCacheName指定的名字的缓存的更新。
	 * @throws IllegalArgumentException 如果更新策略不支持或传入的参数不符合要求。
	 */
	protected void updateCache(final UpdateStrategy updateStrategy, final C updateableValue,
			final boolean integralValue, final String previousCacheName, final boolean skipPreviousCache) {
		if(null != this.parent){
			/** 如果当前缓存为子级缓存，则从父级缓存中更新 */
			parent.updateCache(updateStrategy, updateableValue, integralValue, previousCacheName, skipPreviousCache);
			return;
		}
		checkNotNull(updateStrategy, "updateStrategy can not be null");
		checkNotNull(updateableValue, "updateableValue can not be null");
		writeLock();
		try {
			CompositeKeyCache<C> previousCache = null;
			Object[] args4previous;
			if (previousCacheName == null) {
				args4previous = getArgs4Key(updateableValue);
				if (isValidWrapKey(args4previous)) {
					previousCache = this;
				} else {
					/**
					 * 如果当前缓存为主缓存，且传入的参数数组无效，则尝试从所有级联缓存中查找有效的缓存。
					 * 如果找到有效的缓存，则将其赋值给 previousCache，并获取其参数数组。
					 * 如果没有找到有效的缓存，则直接返回。
					 */
					for (CompositeKeyCache<C> cc : childCachesByName.values()) {
						args4previous = cc.getArgs4Key(updateableValue);
						if (cc.isValidWrapKey(args4previous)) {
							previousCache = cc;
							break;
						}
					}
					if (previousCache == null) {
						return;
					}
				}
			} /*
				 * else if (isValidWrapKey(args4previous = getArgs4Key(updateableValue))) {
				 * previousCache = this; }
				 */else {
				/**
				 * 则尝试从previousCacheName指定的名字的缓存中查找有效的缓存。
				 * 如果找到有效的缓存，则将其赋值给 previousCache，并获取其参数数组。
				 * 如果没有找到有效的缓存，则直接返回。
				 */
				previousCache = checkNotNull(childCachesByName.get(previousCacheName),
						"can not find previousCache by name[%s]", previousCacheName);
				args4previous = previousCache.getArgs4Key(updateableValue);
				if (!previousCache.isValidWrapKey(args4previous)) {
					return;
				}
			}
			/** 保存在缓存中的完整值，可能为null */
			C previousCachedValue = previousCache.getIfPresentUncheck0(args4previous);
			C refreshedValueByPreviousCache = updateableValue;
			final CompositeKeyCache<C> firstCacheWithInvalidArgs = findFirstCacheForInvalidArgs(updateableValue, previousCache);
			/** 
			 * NOTE:
			 * refreshedValueByPreviousCache 是否为合成对象，
			 * 如果是合成的，代表缓存中有缓存对象，并且主键及子键缓存已经同步被更新了，因为主键及子键缓存的是同一对象
			 * 对REPLACE,ALWAYS策略可以直接返回了。
			 */
			AtomicBoolean synthetic = new AtomicBoolean();
			if (this == firstCacheWithInvalidArgs || (!integralValue && null != firstCacheWithInvalidArgs)) {
				/** 如果主键无效,或子键包含无效参数,且updateableValue为非完整值时需要刷新 */
				refreshedValueByPreviousCache = previousCache.refreshOrSynthesize0(args4previous, 
						updateableValue, synthetic);
			}
			if (synthetic.get() && firstCacheWithInvalidArgs == null
					&& (UpdateStrategy.REPLACE == updateStrategy || UpdateStrategy.ALWAYS == updateStrategy)) {
				/** 如果是合成的，代表缓存中有缓存对象，并且主键及子键缓存已经同步被更新了，因为主键及子键缓存的是同一对象 */
				return;
			}
			doUpdateCache0(updateStrategy, updateableValue, integralValue, skipPreviousCache, previousCache,
					previousCachedValue, refreshedValueByPreviousCache);
			/** 根据缓存更新策略更新级联缓存 */
			for (CompositeKeyCache<C> cc : childCachesByName.values()) {
				cc.doUpdateCache0(updateStrategy, updateableValue, integralValue, skipPreviousCache,
						previousCache, previousCachedValue, refreshedValueByPreviousCache);
			}
			if(updateStrategy == UpdateStrategy.ALWAYS || updateStrategy == UpdateStrategy.REPLACE) {
				/** 如果缓存更新策略为 ALWAYS 或者 REPLACE，则调用 onCacheDone */
				onCacheDone(updateableValue);
			}
		} finally {
			writeUnlock();
		}
	}

	private static Object[] wrapArgs4Key(Object[] args) {
		return new Object[] { args };
	}
	/**
	 * <p>
	 * 该异常类继承自 {@link RuntimeException}，用于封装在执行计算过程中发生的异常。
	 * 当在获取缓存值的过程中，调用 {@link #compute(Object[])} 方法发生异常时，
	 * 会将该异常封装为 {@code ComputeException} 抛出。
	 * </p>
	 */
	public static class ComputeException extends RuntimeException {
		private static final long serialVersionUID = 9043337233189596255L;
		public ComputeException(Throwable cause) {
			super(cause);
		}
	}
}
